package com.aididi.common;

import com.aididi.common.constant.SystemConstant;
import com.aididi.common.entity.CheckResult;
import io.jsonwebtoken.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.bouncycastle.util.encoders.Base64;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName JwtUtil
 * @Description jwt
 * @Author xuzexiang
 * @Data 2019/8/21 13:28
 */
@Slf4j
public class JwtUtil {
    /**
     * @Description jwt生成token
     * @return java.lang.String
     * @param [id, subject, ttlMillis]
     * @Author xuzexiang
     * @Date 2019/8/21 14:32
     **/
    public static String createJwt(String id,String subject,long ttlMillis){
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        Long nowMillis = System.currentTimeMillis();
        Map<String,Object> claims = new HashMap<>();
        SecureRandomNumberGenerator secureRandom = new SecureRandomNumberGenerator();
        String hex = secureRandom.nextBytes(16).toHex();
        claims.put(SystemConstant.JWT_CLAIMS,hex);
        Date date  = new Date(nowMillis);
        //密钥生成
        SecretKey secretKey  = generalKey();
        JwtBuilder builder = Jwts.builder()
                .setHeaderParam("typ","JWT")
                .setClaims(claims)  //Claim是一些实体（通常指的用户）的状态和额外的元数据，设置它防止被暴力破解
                .setId(id)      //jwt的唯一身份标识，主要用来作为一次性token,从而回避重放攻击
                .setSubject(subject)        //jwt所面向的用户
                .setIssuer("mydidi")    //签发人
                .setIssuedAt(date)  //jwt的签发时间
                .signWith(signatureAlgorithm,secretKey);    //签发使用的算法和盐,用于设置签名秘钥
        if(ttlMillis >0 ){
            long expMills = nowMillis + ttlMillis;
            Date expDate = new Date(expMills);
            builder.setExpiration(expDate);    //jwt过期时间
        }
        return builder.compact();
    }

    /**
     * @Description 密钥生成
     * @return javax.crypto.SecretKey
     * @param []
     * @Author xuzexiang
     * @Date 2019/8/21 15:40
     **/
    public static SecretKey generalKey(){
        //先使用base64对密钥进行解码
        byte[] encodeKey = Base64.decode(SystemConstant.JWT_SECERT);
        // 在使用aes对称加密算法对密钥进行加密
        SecretKey key = new SecretKeySpec(encodeKey,0,encodeKey.length,"AES");
        return key;
    }

    /**
     * @Description 验证jwt
     * @return com.aididi.common.entity.CheckResult
     * @param [jwtStr]
     * @Author xuzexiang
     * @Date 2019/8/21 15:41
     **/
    public static CheckResult validateJwt(String jwtStr){
        CheckResult result = new CheckResult();
        Claims claims = null;
        try {
            claims = parseJWT(jwtStr);
            result.setSuccess(true);
            result.setClaims(claims);
        }catch (ExpiredJwtException e){
            result.setErrCode(SystemConstant.JWT_ERRCODE_EXPIRE);
            result.setSuccess(false);
        }catch (SignatureException e){
            result.setErrCode(SystemConstant.JWT_ERRCODE_FAIL);
            result.setSuccess(false);
        }catch (Exception e) {
            result.setErrCode(SystemConstant.JWT_ERRCODE_FAIL);
            result.setSuccess(false);
        }
        return result;
    }

    /**
     * @Description 解析jwt的payload部分
     * @return io.jsonwebtoken.Claims
     * @param [jwt]
     * @Author xuzexiang
     * @Date 2019/8/21 15:45
     **/
    public static Claims parseJWT(String jwt) {
        //解析加密后的密钥
        SecretKey secretKey = generalKey();
        try {
            return Jwts.parser()
                    .setSigningKey(secretKey)
                    .parseClaimsJws(jwt)
                    .getBody();
        } catch (ExpiredJwtException e) {
           log.error("解析失败"+e);
        } catch (UnsupportedJwtException e) {
            log.error("解析失败"+e);
        } catch (MalformedJwtException e) {
            log.error("解析失败"+e);
        } catch (SignatureException e) {
            log.error("解析失败"+e);
        } catch (IllegalArgumentException e) {
            log.error("解析失败"+e);
        }
        return null;
    }

    public static void main(String[] args) {
        //生成jwt
        String str = createJwt("1","张三",3000);
        System.out.println("生效的jwt："+str);
        //验证jwt有效性
        System.out.println("验证结果"+validateJwt(str).getErrCode());
        System.out.println("id:"+validateJwt(str).getClaims().getId());
        System.out.println("jwt面向的用户:"+validateJwt(str).getClaims().getIssuer());
        System.out.println(validateJwt(str).getClaims());


    }


}
